/*
 * unittest.c : check that we do not break things too often.
 *
 * Written by T.Pierron, Feb 2011.
 */

#include <stdio.h>
#include <math.h>
#include "SIT_P.h"
#include "graphics.h"

static STRPTR tests[] = {
	"0. Plain dialog",
	"1. Basic geometry",
	"2. Geometry reflow (label) 1",
	"3. Geometry reflow (label) 2",
	"4. Hidden controls",
	"5. Geometry reflow (tabs) 1",
	"6. Geometry reflow (tabs) 2",
	"7. Fixed size dialog",
	"8. Tab navigation test",
	"9. Geometry test",
	"10. Canvas refresh",
	"11. Toolbar",
	"12. Groupbox",
	"13. Listbox",
	"14. Tooltip",
	"15. Dynamic menu",
	"16. Modal event loop",
	"17. Splitter",
	"18. Popup menu",
	"19. Test widgets"
};

static void plain_test(SIT_Widget);
static void basic_test(SIT_Widget);
static void label_reflow_1(SIT_Widget);
static void label_reflow_2(SIT_Widget);
static void hiddden_ctrl(SIT_Widget);
static void tab_reflow_1(SIT_Widget);
static void tab_reflow_2(SIT_Widget);
static void fixed_size(SIT_Widget);
static void tabnav(SIT_Widget);
static void geomtest(SIT_Widget);
static void canvasrefresh(SIT_Widget);
static void toolbar(SIT_Widget);
static void groupbox(SIT_Widget);
static void listbox(SIT_Widget);
static void tooltip(SIT_Widget);
static void dynmenu(SIT_Widget);
static void modalloop(SIT_Widget);
static void splitter(SIT_Widget);
static void popupmenu(SIT_Widget);
static void testwidgets(SIT_Widget);

static int dispatch_test(SIT_Widget w, APTR cd, APTR ud)
{
	switch ((ULONG) ud) {
	case 0: plain_test(w); break;
	case 1: basic_test(w); break;
	case 2: label_reflow_1(w); break;
	case 3: label_reflow_2(w); break;
	case 4: hiddden_ctrl(w); break;
	case 5: tab_reflow_1(w); break;
	case 6: tab_reflow_2(w); break;
	case 7: fixed_size(w); break;
	case 8: tabnav(w); break;
	case 9: geomtest(w); break;
	case 10: canvasrefresh(w); break;
	case 11: toolbar(w); break;
	case 12: groupbox(w); break;
	case 13: listbox(w); break;
	case 14: tooltip(w); break;
	case 15: dynmenu(w); break;
	case 16: modalloop(w); break;
	case 17: splitter(w); break;
	case 18: popupmenu(w); break;
	case 19: testwidgets(w); break;
	}
	return 1;
}

int my_main(int nb, char * argv[])
{
	SIT_Widget app = SIT_CreateWidget("UnitTest", SIT_APP, NULL, NULL);
	SIT_Widget dialog, old;
	int i;

	STRPTR cwd;

	SIT_GetValues(app, SIT_CurrentDir, &cwd, NULL);
	fprintf(stderr, "cwd = %s\n", cwd);

//	popupmenu(app);
//	return SIT_Main();

	dialog = SIT_CreateWidget("UnitTests", SIT_DIALOG, app,
		SIT_Title,   "SIT unit tests",
		SIT_Margins, 5, 10, 10, 10,
		NULL
	);

	for (i = 0, old = NULL; i < DIM(tests); i ++)
	{
		SIT_Widget b = SIT_CreateWidget("button", SIT_PUSHBUTTON, dialog,
			SIT_Title,    tests[i],
			SIT_Margins,  0, 15, 0, 15,
			SIT_MaxWidth, old,
			SIT_Top,      old ? SITV_AttachWidget : SITV_AttachForm, old, 5,
			SIT_LeftAttachment, SITV_AttachForm,
			SIT_RightAttachment, SITV_AttachForm,
			NULL
		);
		SIT_AddCallback(b, SITE_OnActivate, dispatch_test, (APTR) i);
		old = b;
	}
	SIT_ManageWidget(dialog);

	return SIT_Main();
}

/*
 * Plain test
 */
static int save_coord(SIT_Widget w, APTR cd, APTR ud)
{
	int * pos = ud;
	SIT_GetValues(w, SIT_X, pos, SIT_Y, pos+1, NULL);
	return 1;
}

static int paintpat(SIT_Widget d, APTR gc, APTR ud)
{
	int w, h, i;
	GFX_SetPatBrush(gc, ud);
	SIT_GetValues(d, SIT_Width, &w, SIT_Height, &h, NULL);
	for (i = 0; i < h; i += 16)
		GFX_FillRect(gc, 0, i, w-1, i+15);
	return 1;
}

static int freeimg(SIT_Widget w, APTR cd, APTR ud)
{
	GFX_FreeImage(ud);
	return 1;
}

static void plain_test(SIT_Widget parent)
{
	static int pos[] = {40, 40};
	static uint8_t pat[] = {0xdb, 0xb0, 0xdb, 0xff, 0xff, 0xdb, 0xb0, 0xdb, 0xff, 0xff};
	Image img = GFX_CreateImage(10, 10, 8);
	SIT_Widget dialog = SIT_CreateWidget("Plain dialog", SIT_DIALOG, parent,
		SIT_Width, 400, SIT_Height, 300, SIT_X, pos[0], SIT_Y, pos[1], NULL);
	DATA8 p = img->bitmap;
	int i;

	memcpy(p, pat, sizeof pat); p += img->stride;
	memcpy(p, pat, sizeof pat); p += img->stride;

	for (i = 2; i < 10; i += 2, p += img->stride<<1)
	{
		memcpy(p, p-img->stride+1, sizeof pat-1); p[sizeof pat-1] = p[-img->stride];
		memcpy(p+img->stride, p, sizeof pat);
	}

	SIT_AddCallback(dialog, SITE_OnClose, save_coord, pos);
	SIT_AddCallback(dialog, SITE_OnPaint, paintpat, img);
	SIT_AddCallback(dialog, SITE_OnFinalize, freeimg, img);
	SIT_ManageWidget(dialog);
}

/*
 * Basic test
 */
static int handle_paint(SIT_Widget w, APTR gc, APTR ud)
{
	STRPTR title = "\xE2\x96\xA0 Application's title";
	Rect r;
	SIT_GetValues(w, SIT_Rect, &r.x, &r.y, &r.width, &r.height, NULL);
	r.x = r.y = 0;
	GFX_FillGradient(gc, &r, 270, RGB(240, 240, 240), RGB(192, 192, 192), GFX_ColorStop);
	GFX_SetDrMd(gc, GFX_MODEJAM1);
	GFX_SetTextColor(gc, RGB(255, 255, 255));
	GFX_Text(gc, title, -1, 10, 6);
	GFX_SetTextColor(gc, 0);
	GFX_Text(gc, title, -1, 10, 5);
	return 1;
}

int handle_resize(SIT_Widget b, APTR cd, APTR ud)
{
	ULONG * sz = cd;
	ULONG   g, i, j;
	DATA8   p, s;
	if (sz[0] <= 8 || sz[1] <= 8) return 1;
	Image img = GFX_CreateImage(sz[0] - 8, sz[1] - 8, 24);

	SIT_GetValues(b, SIT_UserData, &g, NULL);

	for (j = 0, p = img->bitmap; j < img->height; j ++, p += img->stride)
	{
		for (i = 0, s = p; i < img->width; i ++, s += 3)
		{
			s[0] = 0; s[1] = g; s[2] = 255;
		}
	}

	SIT_SetValues(b, SIT_IconImage, img, SIT_IconOrient, SITV_IconOrientCenter, NULL);

	return 1;
}

int change_label(SIT_Widget w, APTR cd, APTR ud)
{
	fprintf(stderr, "Setting dialog's width...\n");
	SIT_SetValues(ud, SIT_Width, 300, NULL);
	return 0;
}

static int draw_biome(SIT_Widget w, APTR gc, APTR ud)
{
	TextFont info;
	Rect     rect;
	int      item = GFX_GetStage(gc), x, y;
	STRPTR   label;

	SIT_ComboGetRowTag(w, item & 31, &label);
	GFX_GetRefresh(gc, &rect);

	x = 6; y = rect.y + ((rect.height - 15) >> 1);
	GFX_GetFontInfo(gc, &info);
	GFX_SetSysColor(gc, (item & (1<<31)) ? GFX_ColorBgHighlight : GFX_ColorBgWindow, True);
	GFX_FillRectS(gc, &rect);
	GFX_GetRefresh(gc, &rect);
	GFX_Move(gc, x, y+15);
	GFX_3dRect(gc, x, y, 16, 16, 31, False);
	GFX_SetPen(gc, 0, SYSCOL(GFX_ColorBgDialog));
	GFX_DrawRect(gc, x+1, y+1, x+13, y+13);
	GFX_SetBgColor(gc, RGB(255,20,20));
	GFX_FillRect(gc, x+2, y+2, x+12, y+12);
	GFX_SetSysColor(gc, item & (1<<31) ? GFX_ColorFgHighlight : GFX_ColorText, False);
	GFX_Text(gc, label, -1, x+20, rect.y + ((rect.height - info.height) >> 1));

	return 1;
}

static int move_diag(SIT_Widget w, APTR gc, APTR ud)
{
	int x, y;
	SIT_GetValues(ud, SIT_X, &x, SIT_Y, &y, NULL);
	SIT_SetValues(ud, SIT_X, x+10, SIT_Y, y+10, NULL);
	return 1;
}

static int handle_scroll(SIT_Widget w, APTR pos, APTR ud)
{
	fprintf(stderr, "scrollbar pos = %lu\n", (ULONG) pos);
	return 1;
}

static void basic_test(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("MainWnd", SIT_DIALOG, parent,
		SIT_Title,      "Basic geometry test",
		SIT_Margins,    8, 8, 8, 8,
//		SIT_Background, RGB(20, 20, 240),
		NULL
	);

	SIT_CreateWidgets(dialog,
		"<button name=pb1 title='Push me !' right=FORM>"
		"<label name=label1 title='A label' alignHoriz=", SITV_AlignRight, "top=MIDDLE,pb1>"
		"<button name=pb2 title='Change label' right=FORM top=WIDGET,pb1,5>"
		"<label name=label2 alignHoriz=", SITV_AlignRight, "left=FORM top=MIDDLE,pb2 right=WIDGET,pb2,5>"
		"<editbox name=edit title='Content of edit box' top=WIDGET,pb2,5 right=FORM left=FORM>"
		"<canvas name=contain left=FORM right=FORM top=WIDGET,edit,5/>" // frameStyle=", SITV_SunkenThick, "/>"
		"<canvas name=title font='Arial/Bold/120%' height=", SITV_EmOff(100, 10), "frameStyle=", SITV_Sunken,
		" left=FORM right=FORM top=WIDGET,contain,3/>"
		"<progress name=prog progressPos=25 left=FORM right=FORM top=WIDGET,title,5>"
		"<frame name=frame title='Radio buttons' top=WIDGET,prog,3 left=FORM right=FORM>"
		"  <button name=radio1 title='Radio button no 1' buttonType=", SITV_RadioButton, "checkState=1 left=FORM right=FORM>"
		"  <button name=radio2 title='Radio button no 2' buttonType=", SITV_RadioButton, "top=WIDGET,radio1 left=FORM right=FORM>"
		"  <button name=radio3 title='Radio button no 3' buttonType=", SITV_RadioButton, "top=WIDGET,radio2 left=FORM right=FORM>"
		"</frame>"
		"<combobox name=combo readOnly=1 top=WIDGET,frame,5 left=FORM right=FORM>"
		"<scrollbar name=sb maxValue=10 pageSize=1 right=FORM top=WIDGET,combo,5 height=16 horizScroll=1 left=FORM>"
	);
	SIT_SetAttributes(dialog, "<pb1 left=WIDGET,label1,5>");

	SIT_AddCallback(SIT_GetById(dialog, "pb2"), SITE_OnActivate, change_label, dialog); //SIT_GetById(dialog, "label1"));
//	SIT_AddCallback(radio, SIT_OnActivate, layout, dialog);
	SIT_AddCallback(SIT_GetById(dialog, "title"), SITE_OnPaint, handle_paint, NULL);
	SIT_AddCallback(SIT_GetById(dialog, "sb"), SITE_OnScroll, handle_scroll, NULL);

	int i;
	SIT_Widget ctrls[8], ctrl = SIT_GetById(dialog, "contain");
	#define	HALF   (DIM(ctrls)/2)
	for (i = 0; i < DIM(ctrls); i ++)
	{
		ctrls[i] = SIT_CreateWidget("color", SIT_PUSHBUTTON, ctrl,
			SIT_Title,        "",
			SIT_Left,         SITV_AttachPosition, SITV_AttachPos((i&(HALF-1))*(100./HALF)), -3,
			SIT_Top,          i < HALF ? SITV_AttachForm : SITV_AttachWidget, i < HALF ? NULL : ctrls[i-HALF], 3,
			SIT_UserData,     i * 255 / (DIM(ctrls)-1),
			SIT_ResizePolicy, SITV_Fixed,
			NULL
		);
		SIT_AddCallback(ctrls[i], SITE_OnResize, handle_resize, NULL);
		switch (i) {
		case 0:
		case HALF: break;
		case DIM(ctrls)-1:
		case HALF-1:  SIT_SetValues(ctrls[i], SIT_RightAttachment, SITV_AttachForm, NULL); // break;
		default: SIT_SetValues(ctrls[i-1], SIT_Right, SITV_AttachWidget, ctrls[i], 3, NULL);
		}
	}
	#undef HALF

	ctrl = SIT_GetById(dialog, "combo");
	SIT_AddCallback(ctrl, SITE_OnPaint, draw_biome, NULL);
	for (i = 0; i < 10; i ++)
		SIT_ComboInsertItem(ctrl, -1, "abc def ghi", NULL);

	SIT_AddCallback(SIT_GetById(dialog, "pb1"), SITE_OnActivate, move_diag, dialog);

	SIT_ManageWidget(dialog);
}

/*
 * Label reflow: simple test for easier debugging
 */
static int resize_diag(SIT_Widget w, APTR cd, APTR ud)
{
	LONG dir = (LONG) ud;
	int  width;
	SIT_GetValues(w, SIT_Parent, &w, NULL);
	SIT_GetValues(w, SIT_Width, &width, NULL); width += dir;
	fprintf(stderr, "setting width to %d\n", width);
	SIT_SetValues(w, SIT_Width, width, NULL);
	return 1;
}

static int set_size(SIT_Widget w, APTR cd, APTR ud)
{
	ULONG * sz = cd;
	TEXT    szbuf[32];
	sprintf(szbuf, "%ldx%ld", sz[0], sz[1]);
	SIT_SetValues(ud, SIT_Title, szbuf, NULL);
	return 1;
}

static void label_reflow_1(SIT_Widget parent)
{
	static TEXT blurb[] =
		"Graphics is a small, but crude, module integrated into SIT to do basic "
		"graphics operations, like drawing lines, rectangles, bitmaps and text. Its "
		"capabilities are somewhat limited to keep the overhead low, although it is "
		"possible to use external libraries, like GDI+ or Cairo.";
	static TEXT blurb2[] =
		"You can resize horizontally this dialog and see how the height is automatically "
		"adjusted when words are wrapped.";

	SIT_Widget dialog = SIT_CreateWidget("SIT test", SIT_DIALOG, parent,
		SIT_Margins, 15, 20, 15, 20,
//		SIT_Width,   400,
		NULL
	);
	SIT_CreateWidgets(dialog,
		"<frame name=frame title='labels' left=FORM right=FORM>"
		"  <label name=reflow left=FORM right=FORM width=198 minWidth=100 background=", RGB(255,255,0),
		"   title=", blurb, ">"
		"  <label name=reflow2 left=FORM right=FORM font='Georgia/bold' minWidth=100"
		"   title=", blurb2, "top=WIDGET,reflow,15>"
		"</frame>"
		"<button name=add title=+ top=WIDGET,frame,5>"
		"<button name=sub title=- right=FORM top=OPPOSITE,add maxWidth=add margins=0,15,0,15>"
//		"<label name=sz title='' left=WIDGET,add,5 right=WIDGET,sub,5 top=MIDDLE,add>"
	);
	SIT_AddCallback(dialog, SITE_OnResize, set_size, SIT_GetById(dialog, "sz"));
	SIT_AddCallback(SIT_GetById(dialog, "add"), SITE_OnActivate, resize_diag, (APTR) 50);
	SIT_AddCallback(SIT_GetById(dialog, "sub"), SITE_OnActivate, resize_diag, (APTR) -1);
	SIT_ManageWidget(dialog);
}

/*
 * Automatic label reflow within a height-constraint dialog
 */
static void label_reflow_2(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("SIT test", SIT_DIALOG, parent,
		SIT_Margins,  15, 20, 15, 20,
		SIT_MinWidth, 150,
		NULL
	);

	SIT_Widget label = SIT_CreateWidget("User :", SIT_LABEL, dialog,
		SIT_Font, "System/bold", NULL
	);

	SIT_Widget ctrl = SIT_CreateWidget("userlist", SIT_COMBOBOX, dialog,
		SIT_ReadOnly,        True,
		SIT_InitialValues,   "John Doe\tAdd new...",
		SIT_Left,            SITV_AttachWidget, label, 10,
		SIT_RightAttachment, SITV_AttachForm,
		NULL
	);
	SIT_SetValues(label, SIT_Top, SITV_AttachMiddle, ctrl, 0, NULL);

	SIT_Widget form = SIT_CreateWidget("Profile :", SIT_FRAME, dialog,
		SIT_LeftAttachment,  SITV_AttachForm,
		SIT_RightAttachment, SITV_AttachForm,
		SIT_Top,             SITV_AttachWidget, ctrl, 10,
		NULL
	);

	label = SIT_CreateWidget("Name :", SIT_LABEL, form, SIT_AlignHoriz, SITV_AlignRight, NULL);
	ctrl  = SIT_CreateWidget("John Doe", SIT_EDITBOX, form,
		SIT_Left,  SITV_AttachWidget,   label, 10,
		SIT_Right, SITV_AttachPosition, SITV_AttachPos(60), 0,
		NULL
	);

	SIT_Widget label2 = SIT_CreateWidget("Login :", SIT_LABEL, form,
		SIT_Left, SITV_AttachWidget, ctrl, 10,
		NULL
	);
	ctrl = SIT_CreateWidget("JD", SIT_EDITBOX, form,
		SIT_Left,            SITV_AttachWidget, label2, 10,
		SIT_RightAttachment, SITV_AttachForm,
		NULL
	);
	SIT_SetValues(label2, SIT_Top, SITV_AttachMiddle, ctrl, 0, NULL);
	SIT_SetValues(label,  SIT_Top, SITV_AttachMiddle, ctrl, 0, NULL);

	label = SIT_CreateWidget("Password :", SIT_LABEL, form,
		SIT_MaxWidth,   label,
		SIT_AlignHoriz, SITV_AlignRight,
		NULL
	);
	ctrl  = SIT_CreateWidget("password", SIT_EDITBOX, form,
		SIT_Title, "",
		SIT_Left,  SITV_AttachWidget,   label, 10,
		SIT_Right, SITV_AttachPosition, SITV_AttachPos(60), 0,
		SIT_Top,   SITV_AttachWidget,   ctrl, 10,
		NULL
	);
	SIT_SetValues(label, SIT_Top, SITV_AttachMiddle, ctrl, 0, NULL);

	ctrl = SIT_CreateWidget("password2", SIT_EDITBOX, form,
		SIT_Title,           "",
		SIT_Left,            SITV_AttachWidget, ctrl, 10,
		SIT_RightAttachment, SITV_AttachForm,
		SIT_Top,             SITV_AttachOpposite, ctrl, 0,
		NULL
	);

	label = SIT_CreateWidget("Description :", SIT_LABEL, form,
		SIT_MaxWidth,   label,
		SIT_AlignHoriz, SITV_AlignRight,
		NULL
	);
	ctrl  = SIT_CreateWidget("desc", SIT_EDITBOX, form,
		SIT_Title,           "",
		SIT_Left,            SITV_AttachWidget, label, 10,
		SIT_RightAttachment, SITV_AttachForm,
		SIT_Top,             SITV_AttachWidget, ctrl, 10,
		NULL
	);
	SIT_SetValues(label, SIT_Top, SITV_AttachMiddle, ctrl, 0, NULL);

	label = SIT_CreateWidget("Language :", SIT_LABEL, form,
		SIT_MaxWidth,   label,
		SIT_AlignHoriz, SITV_AlignRight,
		NULL
	);
	ctrl  = SIT_CreateWidget("lang", SIT_COMBOBOX, form,
		SIT_ReadOnly,        True,
		SIT_InitialValues,   "English\tFran\xC3\xA7""ais\tDeutsch",
		SIT_Left,            SITV_AttachWidget, label, 10,
		SIT_RightAttachment, SITV_AttachForm,
		SIT_Top,             SITV_AttachWidget, ctrl, 10,
		NULL
	);
	SIT_SetValues(label, SIT_Top, SITV_AttachMiddle, ctrl, 0, NULL);

	label = SIT_CreateWidget("Class :", SIT_LABEL, form,
		SIT_MaxWidth,   label,
		SIT_AlignHoriz, SITV_AlignRight,
		NULL
	);
	ctrl  = SIT_CreateWidget("Administrator", SIT_LABEL, form,
		SIT_Left,            SITV_AttachWidget, label, 10,
		SIT_RightAttachment, SITV_AttachForm,
		SIT_Top,             SITV_AttachWidget, ctrl, 10,
		NULL
	);
	SIT_SetValues(label, SIT_Top, SITV_AttachMiddle, ctrl, 0, NULL);

	label = SIT_CreateWidget("Note :", SIT_LABEL, form,
		SIT_MaxWidth,   label,
		SIT_AlignHoriz, SITV_AlignRight,
		NULL
	);
	ctrl  = SIT_CreateWidget(
		"Leave both password fields blank to do not change it. "
		"If filled, both must case-sensitively match.", SIT_LABEL, form,
		SIT_Left,            SITV_AttachWidget, label, 10,
		SIT_RightAttachment, SITV_AttachForm,
		SIT_Top,             SITV_AttachWidget, ctrl, 10,
		SIT_Width,           250,
		SIT_MinWidth,        100,
		NULL
	);
	SIT_SetValues(label, SIT_Top, SITV_AttachOpposite, ctrl, 0, NULL);

	ctrl = SIT_CreateWidget("Save", SIT_PUSHBUTTON, dialog,
		SIT_Top,      SITV_AttachWidget, form, 10,
		NULL
	);
//	SIT_AddCallback(ctrl, SITE_OnActivate, flash, dialog);

	ctrl = SIT_CreateWidget("Delete", SIT_PUSHBUTTON, dialog,
		SIT_Enabled,  False,
		SIT_MaxWidth, ctrl,
		SIT_Top,      SITV_AttachWidget, form, 10,
		SIT_Left,     SITV_AttachPosition, SITV_AttachPos(50), SITV_OffsetCenter,
		SIT_Margins,  0, 10, 0, 10,
		NULL
	);

	ctrl = SIT_CreateWidget("Cancel", SIT_PUSHBUTTON, dialog,
		SIT_MaxWidth,        ctrl,
		SIT_Top,             SITV_AttachWidget, form, 10,
		SIT_RightAttachment, SITV_AttachForm,
		NULL
	);

	SIT_ManageWidget(dialog);
}

/*
 * Hidden controls:
 *
 */
static int expand(SIT_Widget w, APTR cd, APTR ud)
{
   SIT_Widget list = SIT_GetById(ud, "srvlist");
   Bool visible;

   SIT_GetValues(list, SIT_Visible, &visible, NULL);
   SIT_SetValues(list, SIT_Visible, !visible, NULL);

   SIT_SetAttributes(ud, visible ?
      "<sep1 bottom=NONE top=WIDGET,server,5><pblogin bottom=NONE top=WIDGET,sep1,5><expand title=&#x25BC;>" :
      "<sep1 bottom=WIDGET,pblogin,5 top=NONE><pblogin bottom=FORM top=NONE><expand title=&#x25B2;>");

   return 1;
}

static void hiddden_ctrl(SIT_Widget parent)
{
   SIT_Widget ctrl = NULL;
   SIT_Widget dialog = SIT_CreateWidget("loginscr", SIT_DIALOG, parent,
      SIT_Title,   "Login",
      SIT_Margins, 10, 10, 10, 10,
      NULL
   );

   SIT_CreateWidgets(dialog,
      "<editbox name=login width=250 minWidth=100 buddyLabel=", "&Login :", &ctrl, ">"
      "<editbox name=passwd editType=", SITV_Password, "buddyLabel=", "&Password :", &ctrl, ">"
      "<editbox name=server buddyLabel=", "&Server :", &ctrl, ">"
      "<button name=expand title=&#x25BC; font=Arial>"
      "<listbox name=srvlist columnNames='Name\tAddress\tMachine' visible=0"
      " columnWidths='2*\t*\t*' listBoxFlags=", SITV_FullRowSelect, "height=80>"
      "<label name=sep1 frameStyle=", SITV_EtchedHoriz, ">"
      "<button name=pblogin title=Lo&gin buttonType=", SITV_DefaultButton, ">"
      "<button name=cancel title=&Exit buttonType=", SITV_CancelButton, ">"
   );

   SIT_Widget list = SIT_GetById(dialog, "srvlist");
   SIT_ListInsertItem(list, -1, NULL, NULL, "PPIT v3.5.2.5", "127.0.0.1", "S1", NULL);
   SIT_ListInsertItem(list, -1, NULL, NULL, "PPIT v3.6.0.1", "127.0.0.1", "LAB1430", NULL);
   SIT_ListInsertItem(list, -1, NULL, NULL, "PPIT v3.6.0.1", "127.0.0.1", "D5KV3JM1", NULL);
   SIT_AddCallback(SIT_GetById(dialog, "expand"), SITE_OnActivate, expand, dialog);

   SIT_SetAttributes(dialog,
      "<login right=FORM>"
      "<passwd top=WIDGET,login,5 right=FORM visible=0>"
      "<bpasswd visible=0>"
      "<server top=WIDGET,passwd,5 right=WIDGET,expand,5>"
      "<expand right=FORM top=MIDDLE,server>"
      "<srvlist left=FORM right=FORM top=WIDGET,server,5 bottom=WIDGET,sep1,5>"
      "<sep1 top=WIDGET,server,5 left=FORM,,-10 right=FORM,,-10>"
      "<pblogin margins=0,10,0,10 top=WIDGET,sep1,5>"
      "<cancel maxwidth=pblogin top=OPPOSITE,pblogin,0 right=FORM left=NOOVERLAP,pblogin,10>"
   );
   SIT_ManageWidget(dialog);
}

/*
 * Tab Reflow 1
 * Check AutoHide features of tab: dialog should be enlarged/reduced consistently
 * (no runaway dialog size). Caveat on XP: buttons are clipped by up-down control
 * that appears when there is not enough space to display all tabs :-/
 */
static int addtab(SIT_Widget w, APTR cd, APTR ud)
{
	TEXT tab[32];
	int i;
	SIT_GetValues(ud, SIT_TabCount, &i, NULL);
	sprintf(tab, "Tab %d", i+1);
	SIT_TabSplice(ud, -1, 0, tab, NULL);
	return 1;
}

static int deltab(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_TabSplice(ud, -1, 1, NULL);
	return 1;
}

static void tab_reflow_1(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("MainWnd", SIT_DIALOG, parent,
		SIT_Title,   "Taiste",
		SIT_Margins, 10, 10, 10, 10,
		SIT_Styles,  SITV_DoubleBuffer,
		NULL
	);

	SIT_CreateWidgets(dialog,
		"<tab name=tab left=FORM top=FORM right=FORM>"
		"  <label name=lab title='Hello world! Hello world!'>"
		"  <button name=set title='Add tab' top=WIDGET,lab,5>"
		"  <button name=del title='Del tab' left=WIDGET,set,5 top=OPPOSITE,set>"
		"  <editbox name=edit title='A message to edit' top=WIDGET,del,5 left=FORM right=FORM>"
		"  <canvas name=paint left=FORM right=FORM height=30 top=WIDGET,edit,5/>"
		"  <combobox name=cb top=WIDGET,paint,5 initialValues='First val\tSecond val\tThird val' left=FORM right=FORM>"
		"  <progress name=pg top=WIDGET,cb,9 progressPos=50 left=FORM right=FORM>"
		"</tab>"
		"<button name=thing title='Hello world!' bottom=FORM>"
	);
	SIT_SetAttributes(dialog, "<tab bottom=WIDGET,thing,5>");
	SIT_TabSplice(SIT_GetById(dialog, "tab"), -1, 0, "First tab", NULL);
//	SIT_DumpGeom(dialog);
//	SIT_AddCallback(SIT_GetById(dialog, "paint"), SITE_OnPaint, handle_paint, NULL);
	SIT_AddCallback(SIT_GetById(dialog, "set"), SITE_OnActivate, addtab, SIT_GetById(dialog, "tab"));
	SIT_AddCallback(SIT_GetById(dialog, "del"), SITE_OnActivate, deltab, SIT_GetById(dialog, "tab"));
	SIT_ManageWidget(dialog);
}

/*
 * fixed size dialogs
 * Check SITV_Optimal resize policy (require specific code path for this one).
 */

#define	CELL_HEIGHT       20
#define	CELL_WIDTH        20

static SIT_MenuStruct menu[] =
{
	{1, "&Game", NULL, 0, 100},
		{2, "&Start",    "N", 0, 101},
		{2, "S&ettings", NULL, 0, 1020},
			{3, "Easy",      NULL, SITM_Toggle(103) | SITM_Checked, 102},
			{3, "Normal",    NULL, SITM_Toggle(104), 103},
			{3, "Expert",    NULL, SITM_Toggle(105), 104},
			{3, "Custom...", "C", 0, 105},
		{2, "&Auto discover"},
			{3, "Empty cells only",  NULL, SITM_Toggle(1081), 1080},
			{3, "Obvious flags",     NULL, SITM_Checked, 1081},
			{3, "Show probability",  NULL, 0, 1082},
		{2, "S&cores...", "H", SITM_Disabled, 106},
		{2, SITM_SEPARATOR},
		{2, "E&xit",      "Q",  0, 107},
	{0}
};

static int set_width(SIT_Widget w, APTR cd, APTR ud)
{
	int width;
	SIT_Widget diag;
	SIT_GetValues(ud, SIT_Width, &width, SIT_Parent, &diag, NULL);
	SIT_SetValues(diag, SIT_Title, "ABCDEF", NULL);
	if (width == 10 * CELL_WIDTH)
		SIT_SetValues(ud, SIT_Width, 20 * CELL_WIDTH, SIT_Height, CELL_HEIGHT * 20, NULL);
	else
		SIT_SetValues(ud, SIT_Width, 10 * CELL_WIDTH, SIT_Height, CELL_HEIGHT * 10, NULL);
	return 1;
}

static int instructions(SIT_Widget w, APTR gc, APTR ud)
{
	GFX_SetBgColor(gc, RGB(0x88,0x88,0x88));
	GFX_Text(gc, "Click on resize button to programmatically resize this dialog", -1, 10, 10);
	GFX_Text(gc, "Dialog size will toggle between 400px and 200px.", -1, 10, 25);
	GFX_Text(gc, "Other controls must adjust accordingly.", -1, 10, 40);
	return 1;
}

static int show_menu(SIT_Widget w, APTR cd, APTR ud)
{
	fprintf(stderr, "Menu selected = %p\n", cd);
	if (cd == (APTR) 107)
	{
		SIT_CloseDialog(w);
	}
	return 1;
}

static int show_exit(SIT_Widget w, APTR cd, APTR ud)
{
	fprintf(stderr, "in exit callback\n");
	return 1;
}

static void fixed_size(SIT_Widget parent)
{
	int width  = 20;
	int height = 20;

	SIT_Widget dialog = SIT_CreateWidget("MainWnd", SIT_DIALOG, parent,
		SIT_Title,        "Fixed size",
		SIT_ResizePolicy, SITV_Optimal,
		SIT_Styles,       SITV_NoResize,
		SIT_Menu,         menu,
		NULL
	);
	SIT_AddCallback(dialog, SITE_OnClose, show_exit, NULL);
	SIT_AddCallback(dialog, SITE_OnMenu, show_menu, NULL);

	/* Create main interface */
	SIT_CreateWidgets(dialog,
		"<canvas name=minecount width=", CELL_WIDTH*3, "height=", CELL_HEIGHT-1, "background=0"
		" left=FORM,,2 top=FORM,,2/>"
		"<canvas name=timecount width=", CELL_WIDTH*3, "height=", CELL_HEIGHT-1, "background=0"
		" top=FORM,,2 right=FORM,,2/>"
		"<button name=start title=Resize left=", SITV_AttachPosition, SITV_AttachPos(50), SITV_OffsetCenter,
		" top=FORM margins=0,10,0,10>"
		"<label name=sep frameStyle=", SITV_EtchedHoriz, "left=FORM right=FORM top=WIDGET,start,2>"
		"<canvas name=drawing width=", width * CELL_WIDTH, "height=", height * CELL_HEIGHT,
		" top=WIDGET,sep,1 background=", RGB(0x88,0x88,0x88), "/>"
		"<statusbar name=status labelSize='100%\t{9999}\t{999999}\t{Ins|Rep}\t{\xE2\x97\x8F REC}\t20'>"
	);
	SIT_GetById(dialog, "status");
	SIT_SetStatusText(dialog, "1000", 1);
	SIT_SetStatusText(dialog, "100000", 2);
	SIT_SetStatusText(dialog, "Ins", 3);
	SIT_SetStatusText(dialog, "\xE2\x97\x8F REC", 4);
	SIT_AddCallback(SIT_GetById(dialog, "start"), SITE_OnActivate, set_width, SIT_GetById(dialog, "drawing"));
	SIT_AddCallback(SIT_GetById(dialog, "drawing"), SITE_OnPaint, instructions, NULL);
	SIT_ManageWidget(dialog);
}

/*
 * TabNav test (Mar 29, 2011)
 * Some weird bug occurred when WS_EX_CONTROLPARENT was always set on canvas:
 * When canvas was the only children of a dialog, hitting any key would make the
 * application completely unresponsive for 1 or 2 seconds. 6 hours lost tracking
 * that shit.
 */
static int kbd(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_OnKey * msg = cd;
	fprintf(stderr, "keycode = %d (0x%x)\n", msg->keycode, msg->keycode);
	return 0;
}

static int autorem(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_RemoveWidget(w);
	SIT_SetFocus(ud);
	return 1;
}

Image INV_FindEdges(Image ref)
{
	if (ref == NULL || ref->bpp < 32) return NULL;

	Image   sel;
	DATA8   s, d;
	ULONG   rgb;
	uint8_t mask[4*3*3];
	int     i, j, k, line;

	sel = GFX_CreateImage(ref->width, ref->height, ref->bpp);
	rgb = GFX_SetSysColor(NULL, GFX_ColorBgHighlight, False);
	line = ref->stride;
	memcpy(sel->bitmap, ref->bitmap, line * ref->height);
	sel->format = ref->format;

	/* Fill dot mask */
	mask[0] = rgb & 0xff;
	mask[1] = (rgb >> 8) & 0xff;
	mask[2] = (rgb >> 16) & 0xff;
	mask[3] = 255;

	/* Pre-multiply */
	#define	DATA32(x)   * (uint32_t *) (x)
	for (i = 4, d = mask+4; i < sizeof mask; i += 4, d += 4)
	{
		DATA32(d) = DATA32(mask);
		d[3] = i == 16 ? 255 : (i & 7) ? 127 : 63;
		d[0] = d[0] * d[3] / 255;
		d[1] = d[1] * d[3] / 255;
		d[2] = d[2] * d[3] / 255;
	}
	DATA32(mask) = DATA32(mask+8);
	int offset[] = {-line-4, -line, -line+4, -4, 0, 4, line-4, line, line+4};

	for (s = ref->bitmap + line + 4, d = sel->bitmap + line + 4, j = ref->height-2; j > 0; j --, s += 8, d += 8)
	{
		for (i = ref->width - 2; i > 0; i --, s += 4, d += 4)
		{
			if (s[3] == 255 && (s[-1] < 192 || s[7] < 192 || s[-line+3] < 192 || s[line+3] < 192))
			{
				DATA8 m, r;
				for (k = 0, m = mask; k < DIM(offset); k ++, m += 4)
				{
					int v;
					r = d + offset[k];
					/* Put a 3x3 alpha-blended dot */
					#define MAX_255(x)   ((v = x) > 255 ? 255 : v)
					#if 1
					r[0] = MAX_255(r[0] * (255-m[3]) / 255 + m[0]);
					r[1] = MAX_255(r[1] * (255-m[3]) / 255 + m[1]);
					r[2] = MAX_255(r[2] * (255-m[3]) / 255 + m[2]);
					r[3] = MAX_255(m[3] + r[3] * (255 - m[3]) / 255);
					#else
					r[0] = m[0];
					r[1] = m[1];
					r[2] = m[2];
					r[3] = m[3];
					#endif
				}
			}
		}
	}
	GFX_ToNativeFormat(ref);
	GFX_ToNativeFormat(sel);
	return sel;
}

static int paint(SIT_Widget w, APTR gc, APTR ud)
{
	Image * ref = ud;
	if (ref[0]) GFX_SetPixels(ref[0], 25, 0, 25, ref[0]->height, gc, 10, 10, 25, ref[0]->height);
	if (ref[1]) GFX_SetPixels(ref[1], 25, 0, 25, ref[1]->height, gc, 10, 40, 25, ref[1]->height);
	return 1;
}

void tabnav(SIT_Widget parent)
{
	static Image ref[2];

	SIT_Widget dialog = SIT_CreateWidget("MainWnd", SIT_DIALOG, parent,
		SIT_Title,      "Tab Navigation",
		NULL
	);

	SIT_CreateWidgets(dialog,
		"<canvas name=draw left=FORM top=FORM bottom=FORM right=FORM width=200 height=250>"
		"  <button name=rem title='Click to remove' X=3 Y=75>"
		"</canvas>"
	);

	SIT_Widget w = SIT_GetById(dialog, "draw");

	if (ref[0] == NULL)
	{
		ref[0] = GFX_LoadImage("raw://../Carto/source/25px-items.png");
		ref[1] = INV_FindEdges(ref[0]);
	}
	SIT_AddCallback(w, SITE_OnRawKey,     kbd, NULL);
	SIT_AddCallback(w, SITE_OnVanillaKey, kbd, NULL);
	SIT_AddCallback(w, SITE_OnPaint,      paint, ref);
	SIT_AddCallback(SIT_GetById(dialog, "rem"), SITE_OnActivate, autorem, w);
	SIT_SetFocus(w);
	SIT_ManageWidget(dialog);
}

/*
 * geomtest: test geometric constraints
 */
#if 0
static int space_even(SIT_Widget w, APTR cd, APTR ud)
{
	int x1, x2, w1, * ret = cd, iud = (ULONG) ud;
	if (ret[2] > 0) return 0;
	SIT_GetValues(w, SIT_UserData, &w, NULL);
	SIT_GetValues(w, SIT_UserData, &w, SIT_X, &x1, SIT_Width, &w1, NULL);
	SIT_GetValues(w, SIT_X, &x2, NULL);
	x1 += w1;
	ret[0] = x1 + (x2-x1-w1*((iud>>8)-1)) * (iud&0xff) / (iud>>8) + w1 * ((iud&0xff)-1);
	return 1;
}

/* XXX way too looong */
static void space_evenly(SIT_Widget parent, STRPTR names, STRPTR attr, int method)
{
	int      nb  = StrCount(names, ',') + 1, i, max;
	STRPTR * cmd = alloca(sizeof *cmd * nb + strlen(names) + 1);
	STRPTR   buf, p;

	Split(cmd, strcpy((STRPTR) (cmd+nb), names), nb, ',');

	for (i = max = 0; i < nb; i ++)
	{
		int len = strlen(cmd[i]) + 1;
		if (len > max) max = len;
	}

	max = max * 3 + (attr ? strlen(attr) : 0) + 32;
	buf = p = alloca(max);
	p += sprintf(buf, "<%s left=%d", cmd[0], SITV_AttachForm);
	if (attr) p += sprintf(p, " %s", attr);
	*p++ = '>'; *p = 0;
	SIT_SetAttributes(parent, buf);
	SIT_Widget first = SIT_GetById(parent, cmd[0]);
	SIT_SetValues(first, SIT_UserData, SIT_GetById(parent, cmd[nb-1]), NULL);

	for (i = 1, nb --; i < nb; i ++)
	{
		SIT_Widget w = SIT_GetById(parent, cmd[i]);
		p = buf + sprintf(buf, "<%s left=%d,%s,5 maxwidth=%s", cmd[i], SITV_AttachNoOverlap, cmd[i-1], cmd[i-1]);
		if (attr) p += sprintf(p, " %s", attr);
		*p++ = '>'; *p = 0;
		SIT_SetAttributes(parent, buf);
		SIT_SetValues(w, SIT_UserData, first, NULL);
		SIT_AddCallback(w, SITE_OnGeometrySet, space_even, (APTR) (i | (nb<<8)));
	}
	sprintf(buf, "<%s right=%d,%s,5>", cmd[i-1], SITV_AttachNoOverlap, cmd[i]);
	SIT_SetAttributes(parent, buf);

	p = buf + sprintf(buf, "<%s right=%d maxwidth=%s", cmd[i], SITV_AttachForm, cmd[i-1]);
	if (attr) p += sprintf(p, " %s", attr);
	*p++ = '>'; *p = 0;
	SIT_SetAttributes(parent, buf);
}

static void geomtest(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("MainWnd", SIT_DIALOG, parent,
		SIT_Title,   "TAISTE",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);
	SIT_Widget list = NULL;

	SIT_CreateWidgets(dialog,
		"<editbox name=find title='' right=FORM buddyLabel=", "Find:", &list, ">"
		"<button name=next title='Find next' top=WIDGET,find,5>"
		"<button name=cancel title=Cancel top=OPPOSITE,next>"
		"<button name=prev title='Find prev' top=OPPOSITE,next>"
		"<button name=rep title=Replace top=OPPOSITE,next>"
		"<button name=repall title='Replace all' top=OPPOSITE,next>"
	);
	space_evenly(dialog, "next,prev,rep,repall,cancel", "margins=1,15,1,15", 0);

	SIT_ManageWidget(dialog);
}
#endif

#if 0
static int space_even(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_Widget parent;
	int x1, x2, w1, iud, * ret = cd;

	if (ret[2] > 0) return 0;
	SIT_GetValues(w, SIT_Parent, &parent, NULL);
	SIT_GetValues(SIT_GetById(parent, "next"), SIT_X, &x1, SIT_Width, &w1, NULL);
	SIT_GetValues(parent, SIT_Width, &x2, NULL);
	x2 -= w1 + 10; x1 += w1;
	iud = ((ULONG) ud+1) | (4<<8);
	ret[0] = x1 + (x2-x1-w1*((iud>>8)-1)) * (iud&0xff) / (iud>>8) + w1 * ((iud&0xff)-1);
	x1 = (w1 + 5) * (iud & 0xff) + 10;
	if (ret[0] < x1) ret[0] = x1;
	return 1;
}

static void geomtest(SIT_Widget parent)
{
	int repmode = 1;
	SIT_Widget dialog = SIT_CreateWidget("find", SIT_DIALOG, parent,
		SIT_Title,   repmode ? "Replace word" : "Find word",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);
	SIT_Widget list = NULL;
	int flags = 3;
	SIT_CreateWidgets(dialog,
		"<editbox name=edit title='' buddyLabel=", "&Find:", &list, "right=FORM font=System/120%>"
		"<button name=case title='&Match case' buttonType=", SITV_CheckBox, "top=WIDGET,edit,5"
		" left=OPPOSITE,edit checkState=", (flags & 1) == 0, ">"
		"<button name=word title='&Word only' buttonType=", SITV_CheckBox, "top=OPPOSITE,case"
		" left=WIDGET,case,10 checkState=", flags & 2, "userData=1>"
		"<button name=regxp title='&Regular expression' buttonType=", SITV_CheckBox,
		" top=OPPOSITE,case left=WIDGET,word,10 checkState=", flags & 4, "userData=2>"
		"<label name=sep frameStyle=", SITV_EtchedHoriz, "left=FORM,,-10 right=FORM,,-10 top=WIDGET,case,10>"
		"<button name=next title='Find &next' margins=1,15,1,15 top=WIDGET,sep,10 buttonType=", SITV_DefaultButton, ">"
		"<button name=prev title='Find &prev' margins=1,15,1,15 top=OPPOSITE,next userData=1 left=",
			SITV_AttachPosition, SITV_AttachPos(50), SITV_OffsetCenter, "maxWidth=next>"
		"<button name=close title=Close margins=1,15,1,15 top=OPPOSITE,next right=FORM buttonType=",
			SITV_CancelButton, "maxWidth=prev>"
	);
	if (repmode)
	{
		SIT_CreateWidgets(dialog,
			"<editbox name=repby title='' buddyLabel=", "&Replace by:", &list, "right=FORM top=WIDGET,edit,5"
			" font=System/120% tabOrder=edit>"
			"<button name=rep tabOrder=prev title=Replace margins=1,15,1,15 top=OPPOSITE,next "
			" maxWidth=prev left=NOOVERLAP,prev,5>"
			"<button name=repall tabOrder=rep title='Replace all' margins=1,15,1,15 top=OPPOSITE,next left=NOOVERLAP,rep,5"
			" maxWidth=rep right=NOOVERLAP,close,5>"
		);
		SIT_SetAttributes(dialog,
			"<close leftObject=repall>"
			"<case topObject=repby>"
			"<prev left=NOOVERLAP,next,5>"
		);
		SIT_AddCallback(SIT_GetById(dialog, "prev"),   SITE_OnGeometrySet, space_even, 0);
		SIT_AddCallback(SIT_GetById(dialog, "rep"),    SITE_OnGeometrySet, space_even, (APTR) 1);
		SIT_AddCallback(SIT_GetById(dialog, "repall"), SITE_OnGeometrySet, space_even, (APTR) 2);
	}
	SIT_SetFocus(SIT_GetById(dialog, "edit"));
	SIT_ManageWidget(dialog);
}
#endif

static STRPTR syscol[] = {
	"Text",
	"Dark shadow",
	"3d face",
	"3d highlight",
	"3d light",
	"3d shadow",
	"Desktop background",
	"Dialog background",
	"Control foreground",
	"Caption foreground",
	"Grayed text",
	"Highlight background",
	"Highlight foreground",
	"Hot link",
	"ToolTip background",
	"ToolTip foreground",
	"Menu background",
	"Menu foreground",
	"Selected menu background",
	"Selected menu foreground",
	"Window background"
};

/* Not so trivial geometry test */
void geomtest(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("ColorChooser", SIT_DIALOG, parent,
		SIT_Title,   "Select color",
		SIT_Styles,  SITV_HasResize,
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);

	#define	XY_WIDTH     150
	#define	XY_HEIGHT    150
	#define	Z_WIDTH      16

	static char image_blob[] =
	#include "bitmap.h"

	int i;
	SIT_Widget lab = NULL;
	SIT_CreateWidgets(dialog,
		"<tab name=tab tabStr='Color\tSystem' margins=2>"
		"  <canvas name=cspaceXY width=", XY_WIDTH, "height=", XY_HEIGHT, "margins=2,2,2,2 "
		"   frameStyle=", SITV_Sunken, "tabOrder=", SITV_TabNum(1, 1), "/>"
		"  <canvas name=cspaceZ margins=2,2,2,2 width=", Z_WIDTH, "frameStyle=", SITV_Sunken,
		"   tabOrder=", SITV_TabNum(1, 2), "/>"
		"  <listbox name=syscol columnNames=Name columnWidths=* tabOrder=", SITV_TabNum(2, 3),
		"   listBoxFlags=", SITV_NoHeaders | SITV_FullRowSelect, ">"
		"</tab>"
		"<label name=labp1 title=Current: alignHoriz=", SITV_AlignRight, ">"
		"<label name=labp2 title=Old: maxWidth=labp1 alignHoriz=", SITV_AlignRight, ">"
		"<canvas name=colpatch1 margins=2,2,2,2 height=16 frameStyle=", SITV_Sunken, "/>"
		"<canvas name=colpatch2 margins=2,2,2,2 height=16 frameStyle=", SITV_Sunken, "/>"
		"<button name=addto title=&#x25BA; margins=0,7,0,7 font=Arial>"
		"<canvas name=library/>"
		"<editbox name=hexval title='#123456' font=System/110% resizePolicy=", SITV_Fixed,
		" buddyLabel=", "HTML notation:", &lab, ">"
		"<button name=picker title='' iconPath=", image_blob, "iconOrient=", SITV_IconOrientCenter, ">"
		"<button name=reset title=Reset margins=1,15,1,15>"
		"<button name=ok title=Ok margins=1,15,1,15 maxWidth=reset buttonType=", SITV_DefaultButton, ">"
		"<button name=cancel title=Cancel margins=1,15,1,15 maxWidth=ok buttonType=", SITV_CancelButton, ">"
	);

	SIT_SetAttributes(dialog,
		"<cspaceZ top=OPPOSITE,cspaceXY bottom=OPPOSITE,cspaceXY left=WIDGET,cspaceXY,2>"
		"<syscol top=FORM left=FORM right=FORM bottom=FORM>"
		"<colpatch1 top=WIDGET,tab,5 left=WIDGET,labp1,5 right=OPPOSITE,tab>"
		"<colpatch2 top=WIDGET,colpatch1,1 left=WIDGET,labp2,5 right=OPPOSITE,tab>"
		"<labp1 top=MIDDLE,colpatch1>"
		"<labp2 top=MIDDLE,colpatch2>"
		"<addto left=WIDGET,colpatch1,10 top=MIDDLE,colpatch1>"
		"<library left=WIDGET,addto,10 top=OPPOSITE,addto right=FORM bottom=OPPOSITE,colpatch2>"
		"<bhexval left=WIDGET,tab,5>"
		"<picker right=FORM top=MIDDLE,hexval>"
		"<reset top=OPPOSITE,cancel right=WIDGET,ok,5>"
		"<ok top=OPPOSITE,cancel right=WIDGET,cancel,5>"
		"<cancel top=WIDGET,colpatch2,4 right=FORM>"
	);

	lab = SIT_GetById(dialog, "syscol");
	for (i = 0; i < DIM(syscol); i ++)
		SIT_ListInsertItem(lab, -1, NULL, NULL, syscol[i], NULL);

	#define	NBCP   12
	#define	HALF   (NBCP/2)
	SIT_Widget preset[NBCP];
	for (i = 0, lab = SIT_GetById(dialog, "library"); i < NBCP; i ++)
	{
		preset[i] = SIT_CreateWidget("color", SIT_PUSHBUTTON, lab,
			SIT_Title,        "",
			SIT_Left,         SITV_AttachPosition, SITV_AttachPos((i%HALF)*(100./HALF)), 3,
			SIT_Bottom,       SITV_AttachPosition, i < HALF ? SITV_AttachPos(50) : SITV_AttachPos(100), -1,
			SIT_Top,          i < HALF ? SITV_AttachForm : SITV_AttachWidget, i < HALF ? NULL : preset[i-HALF], 0,
			SIT_ResizePolicy, SITV_Fixed,
			SIT_UserData,     i * 255 / (NBCP-1),
//			SIT_MinWidth,     22,
			SIT_MinHeight,    16,
			NULL
		);
		SIT_AddCallback(preset[i], SITE_OnResize, handle_resize, NULL);
		switch (i) {
		case 0:
		case HALF: break;
		case NBCP-1:
		case HALF-1: SIT_SetValues(preset[i], SIT_RightAttachment, SITV_AttachForm, NULL); // no break;
		default:     SIT_SetValues(preset[i-1], SIT_Right, SITV_AttachWidget, preset[i], 3, NULL);
		}
	}

	SIT_Widget tab = SIT_GetById(dialog, "tab"), lab2;
	for (i = 0, lab = lab2 = NULL; i < 6; i ++)
	{
		static STRPTR sname[] = {"H", "S", "V", "R", "G", "B"};
		static int    smax[]  = {360, 100, 100, 255, 255, 255};

		lab = SIT_CreateWidget(sname[i], SIT_PUSHBUTTON, dialog,
			SIT_ButtonType, SITV_RadioButton,
			SIT_CheckState, i == 0,
			SIT_Left,       SITV_AttachWidget, tab, 5,
			NULL
		);

		lab2 = SIT_CreateWidget("0", SIT_EDITBOX, dialog,
			SIT_EditType,  SITV_Integer,
			SIT_MaxValue,  smax[i],
			SIT_Top,       i > 0 ? SITV_AttachWidget : SITV_AttachForm, lab2, 2,
			SIT_Right,     SITV_AttachForm, NULL, 0,
			SIT_Width,     50,
			SIT_ScrollPos, 0,
			SIT_ResizePolicy, SITV_Fixed,
			NULL
		);
		SIT_SetValues(lab, SIT_Top, SITV_AttachOpposite, lab2, 0, NULL);

		SIT_CreateWidget("slider", SIT_SLIDER, dialog,
			SIT_MaxValue,   smax[i],
			SIT_Width,      200,
			SIT_TickStyle,  SITV_TicksNone,
			SIT_Left,       SITV_AttachWidget,   lab,  0,
			SIT_Top,        SITV_AttachOpposite, lab2, 0,
			SIT_Right,      SITV_AttachWidget,   lab2, 2,
			SIT_Bottom,     SITV_AttachOpposite, lab2, 0,
			SIT_BuddyEdit,  lab2,
			SIT_ThumbWidth, 16,
			NULL
		);
	}
	SIT_SetAttributes(dialog, "<hexval top=", SITV_AttachWidget, lab, 13, "right=WIDGET,picker,7>");

	SIT_ManageWidget(dialog);
}

/*
 * Canvas Refresh: HREDRAW & VREDRAW
 */
static int refresh_canvas(SIT_Widget w, APTR gc, APTR ud)
{
	static int count = 0;
	TEXT dummy[128];
	int  i;
//	SIT_GetValues(w, SIT_CaretState, &state, NULL);
//	SIT_SetValues(w, SIT_CaretState, SITV_HasCaret, NULL);
	for (i = 0; i < 30; i ++)
	{
		sprintf(dummy, "Hello world on line %d", i);
		GFX_Text(gc, dummy, -1, 10, i * 15);
	}
	sprintf(dummy, "Refresh count %d", ++count);
	GFX_Text(gc, dummy, -1, 10, i * 15);
	GFX_Text(gc, "Shouldn't have any flickering effect while resizing", -1, 200, 0);
	GFX_Text(gc, "No leftover under uncovered area of canvas.", -1, 200, 15);
	GFX_Text(gc, "Refresh count must increase for each resize notification.", -1, 200, 30);

	GFX_SetBgColor(gc, RGB(255, 20, 20));
	GFX_FillRect(gc, 200, 50, 300, 60);
	GFX_SetBgColor(gc, RGB(255, 255, 20));
	GFX_FillRect(gc, 200, 70, 300, 80);
//	if (state & SITV_CaretVisible) SIT_SetValues(w, SIT_CaretState, state, NULL);
	return 1;
}

static int show_clicks(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_OnMouse * msg = cd;
	fprintf(stderr, "click on button: %d, state: %d, pos: %d,%d\n", msg->button, msg->state, msg->x, msg->y);
	return 1;
}

static int show_capture(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_OnMouse * msg = cd;
	if (msg->state == SITOM_CaptureMove)
		fprintf(stderr, "capture move to %dx%d\n", msg->x, msg->y);
	return 0;
}

static int show_size(SIT_Widget w, APTR cd, APTR ud)
{
	ULONG * sz = cd;
	fprintf(stderr, "Canvas size = %lux%lu\n", sz[0], sz[1]);
	return 1;
}

static int set_caret(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_OnKey * msg = cd;
	switch (msg->utf8[0]) {
	case 's': SIT_SetValues(w, SIT_CaretState, SITV_HasCaret | SITV_CaretVisible, NULL); break;
	case 'h': SIT_SetValues(w, SIT_CaretState, SITV_HasCaret, NULL); break;
	case ' ': SIT_SetValues(w, SIT_Width, 550, NULL); break;
	default: fprintf(stderr, "key = %s\n", msg->utf8); return 0;
	}
	return 1;
}

static void canvasrefresh(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("MainWnd", SIT_DIALOG, parent,
		SIT_Title,   "Canvas refresh",
//		SIT_Margins, 10, 10, 10, 10,
		SIT_Menu,    menu,
		NULL
	);
	SIT_CreateWidgets(dialog,
		"<scrollbar name=sb right=FORM top=FORM bottom=FORM>"
		"<canvas name=draw width=600 height=480 left=FORM top=OPPOSITE,sb bottom=OPPOSITE,sb right=WIDGET,sb"
		" userBgClear=1 autofocus=1 caretState=", SITV_CaretVisible | SITV_HasCaret,
		" caretWidth=6 caretHeight=14 caretX=150 caretY=150/>"
	);
	SIT_SetValues(SIT_GetById(dialog, "sb"),
		SIT_Enabled,   False,
		SIT_MaxValue,  10,
		SIT_PageSize,  10,
		SIT_ScrollPos, 0,
		NULL
	);
	SIT_Widget c = SIT_GetById(dialog, "draw");
	SIT_AddCallback(c, SITE_OnPaint, refresh_canvas, NULL);
	SIT_AddCallback(c, SITE_OnClick, show_clicks, NULL);
	SIT_AddCallback(c, SITE_OnMouseMove, show_capture, NULL);
//	SIT_AddCallback(c, SITE_OnResize, show_size, NULL);
	SIT_AddCallback(c, SITE_OnVanillaKey, set_caret, dialog);
	SIT_ManageWidget(dialog);
}


/*
 * Toolbar test
 * Basic toolbar creation with menu interaction
 */
static SIT_MenuStruct tbmenu[] =
{
	{1, "&File"},
		{2, "&New",        "N",  0, 101},
		{2, "&Open",       "O",  0, 102},
		{2, "&Save",       "S",  SITM_Disabled, 103},
		{2, "Save &as...", NULL, 0, 104, 0, "bitmap/new.png"},
		{2, "Bleurp...",   NULL, SITM_Disabled, 106, 0, "bitmap/help-system-16px.bmp"},
		{2, SITM_SEPARATOR},
		{2, "E&xit",       "Q",  0, 105},

	{1, "&Edit"},
		{2, "&Undo",       "U",  0, 201, 0, "bitmap/simple3x3-24.bmp"},
		{2, "&Redo",       "Y",  SITM_Disabled, 202, 0, "bitmap/simple3x3-24.bmp"},
		{2, SITM_SEPARATOR},
		{2, "C&ut",        "X",  0, 203},
		{2, "&Copy",       "C",  0, 204},
		{2, "&Paste",      "V",  SITM_Disabled, 205},
		{2, "&Delete",     NULL, SITM_NoMenuIcon, 206},

	{1, "&Background"},
		{2, "&White",      NULL, SITM_Toggle(302) | SITM_Checked, 301},
		{2, "&Light Gray", NULL, SITM_Toggle(303), 302},
		{2, "&Gray",       NULL, SITM_Toggle(304), 303},
		{2, "&Dark Gray",  NULL, SITM_Toggle(305), 304},
		{2, "&Black",      NULL, 0, 305},
		{2, "Choose...",   NULL, 0, 330},

	{1, "&Timer"},
		{2, "&Start",      "Ctrl+Home", 0,      401},
		{2, "S&top",       NULL, SITM_Disabled, 402},

	{1, "&Help"},
		{2, "&Help...",           NULL, SITM_NoMenuIcon, 501},
		{2, "&About MenuDemo...", NULL, 0, 502, 0, "bitmap/help-system.bmp"},
	{0}
};

static int nuthing(SIT_Widget w, APTR gc, APTR ud)
{
	if (ud)
	{
		Image img = ud;
		GFX_SetPixels(img, 0, 0, img->width, img->height, gc, 0, 0, 0, 0);
	}
	return 1;
}

static int onmenu(SIT_Widget w, APTR cmdId, APTR ud)
{
	static SIT_Widget file;

	switch ((ULONG)cmdId) {
	case 101:
		SIT_SetToolButton(ud, 204, SITTB_Checked, DontChangePtr, DontChangePtr);
		break;
	case 102: // Test open file dialog
		if (file == NULL)
			file = SIT_CreateWidget("fileselect", SIT_FILESELECT, ud, SIT_Filters, "Any\t*", NULL);

		if (SIT_ManageWidget(file))
		{
			STRPTR path;
			int    nb;

			SIT_GetValues(file, SIT_SelPath, &path, SIT_NbSelect, &nb, NULL);

			fprintf(stderr, "select = %s\n", path);

			SIT_SetValues(SIT_GetById(ud, "custom"), SIT_Title, BaseName(path), NULL);
		}
		break;
	case 103:
		fprintf(stderr, "item 110 state: %d\n", SIT_GetMenuState(w, 110));
		fprintf(stderr, "item 111 state: %d\n", SIT_GetMenuState(w, 111));
		fprintf(stderr, "item 306 state: %d\n", SIT_GetMenuState(w, 306));
	}
	return 1;
}

static void toolbar(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("SubDlg", SIT_DIALOG, parent,
		SIT_Title,   "Toolbar test",
		SIT_Menu,    tbmenu,
//		SIT_Width,   300,
		NULL
	);

	static SIT_ToolButton buttons[] = {
		{101, NULL, SITTB_Button|SITTB_AutoTips, SITB_FileNew},
		{102, NULL, SITTB_Button|SITTB_AutoTips, SITB_FileOpen},
		{103, NULL, SITTB_Button|SITTB_AutoTips, SITB_FileSave},
		{110, NULL, SITTB_Button|SITTB_Disabled, "alt:bitmap/new.png", "Open existing file"},
		{SITTB_Separator},
		{301, "Wh", SITTB_Button | SITTB_Toggle(302) | SITTB_Checked},
		{302, "LG", SITTB_Button | SITTB_Toggle(303)},
		{303, "Gr", SITTB_Button | SITTB_Toggle(304)},
		{304, "DG", SITTB_Button | SITTB_Toggle(305)},
		{305, "K",  SITTB_Button},
		{306, "XYZ", SITTB_Button | SITTB_Toggle(0) | SITTB_Checked},
		{SITTB_Separator},
		{501, NULL, SITTB_Button|SITTB_GfxImage},
//		{501, NULL, SITTB_Child},
		{SITTB_Separator},
		{203, NULL, SITTB_Button|SITTB_Toggle(204), SITB_Cut},
		{204, NULL, SITTB_Button, SITB_Copy},
//		{205, NULL, SITTB_Child},
		{205, NULL, SITTB_Button|SITTB_Toggle(0), "bitmap/paste.png"},
		{206, NULL, SITTB_Button|SITTB_AutoTips, SITB_Delete},
		{}
	};

	Image img = GFX_CreateImage(16, 16, 32);
	TEXT rgba[] = {20,20,255,255};
	DATA8 p;
	int i;
	for (i = img->height * img->width, p = img->bitmap; i > 0; memcpy(p, rgba, 4), p += 4, i --);
	buttons[12].icon = (STRPTR) img;

	SIT_CreateWidgets(dialog,
		"<toolbar name=tool toolbarStyle=", SITV_ToolBarList|SITV_SyncWithMenu, "buttonList=", buttons, ">"
//		"  <combobox name=combo readOnly=1 initialValues='First item\tSecond item\tThird item'>"
//		"  <label name=text title='Progress: 5%' marginLeft=5 marginRight=10>"
		"</toolbar>"
		"<canvas name=canvas frameStyle=", SITV_Sunken, "background=0xffffff top=WIDGET,tool"
		" left=FORM right=FORM bottom=FORM height=100>"
	);
	SIT_AddCallback(SIT_GetById(dialog, "combo"), SITE_OnPaint, draw_biome, NULL);
//	SIT_AssignToolButtons(SIT_GetById(dialog, "tool"), buttons, //501, SIT_GetById(dialog, "combo"),
//		205, SIT_GetById(dialog, "text"), 0);
	SIT_AddCallback(SIT_GetById(dialog, "canvas"), SITE_OnPaint, nuthing, GFX_LoadImage("bitmap/help-system-24.bmp"));
	SIT_AddCallback(dialog, SITE_OnMenu, onmenu, SIT_GetById(dialog, "tool"));
	SIT_ManageWidget(dialog);
}

/*
 * Test group box resize/layout
 */
static void groupbox(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("GroupBox", SIT_DIALOG, parent,
		SIT_Title,   "Groupbox test",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);
	SIT_CreateWidgets(dialog,
		"<frame name=set1 title='Frame level 1'>"
		"  <button name=b1 title='Button 1'>"
		"  <frame name=set2 title='Frame level 2' top=WIDGET,b1,5>"
		"    <button name=b2 title='Button 2'>"
		"    <frame name=set3 title='Frame level 3' top=WIDGET,b2,5>"
		"      <button name=b3 title='Button 3'>"
		"    </frame>"
		"  </frame>"
		"</frame>"
	);
	SIT_ManageWidget(dialog);
}

/*
 * Basic listbox test
 */
static int handle_lb_click(SIT_Widget w, APTR cd, APTR ud)
{
	fprintf(stderr, "row selected = %d\n", (int) cd);
	return 0;
}

static int autocomplete(SIT_Widget w, APTR cd, APTR ud)
{
	STRPTR cell;
	ULONG oldlen;
	int i, nb, len = strlen(cd);

	/* Not perfect, but usually quite enough */
	SIT_GetValues(ud, SIT_ItemCount, &nb, SIT_UserData, &oldlen, NULL);
	SIT_SetValues(ud, SIT_UserData, len, NULL);

	if (len <= oldlen) return 0;

	for (i = 0; i < nb; i ++)
	{
		SIT_GetValues(ud, SIT_RowText(i, 0), &cell, NULL);
		if (strncasecmp(cell, cd, len) == 0)
		{
			if (cell[len]) {
				SIT_SetValues(ud, SIT_SelectedIndex, i, NULL);
				SIT_SetValues(w, SIT_Title, cell, SIT_StartSel, len, SIT_EndSel, strlen(cell), NULL);
			}
			break;
		}
	}
	return 0;
}

static int sort_item(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_OnSort * msg = cd;

	switch (msg->column) {
	case 0: return SIT_SortAlphaNum;
	case 1: return SIT_SortNumeric;
	default: return SIT_SortAlpha;
	}
}

static void listbox(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("ListBox", SIT_DIALOG, parent,
		SIT_Title,   "Listbox test",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);

	SIT_CreateWidgets(dialog,
		"<frame name=frame title=Levels left=FORM right=FORM>"
		"  <listbox name=list sortColumn=0 columnNames='first value\tsecond value\tthird value'"
		"   columnWidths='2*,*,*' listBoxFlags=", SITV_FullRowSelect | SITV_SelectMultiple,
		"   left=FORM right=FORM width=250 minWidth=150 height=100>"
		"  <editbox name=edit left=FORM top=WIDGET,list,5 right=FORM>"
		"</frame>"
	);

	SIT_Widget cb = SIT_GetById(dialog, "list");
	SIT_Widget edit = SIT_GetById(dialog, "edit");
	#if 0
	SIT_ListInsertItem(cb, -1, NULL, NULL, "Hello", "World!", "...", NULL);
	SIT_ListInsertItem(cb, -1, NULL, NULL, "Abc", "xYZ", NULL);
	SIT_ListInsertItem(cb, -1, NULL, NULL, "QWER", "TYUI", "OP^$", NULL);
	SIT_ListInsertItem(cb, -1, NULL, NULL, "taiste", "test", "wwwwww", NULL);
	SIT_ListInsertItem(cb, -1, NULL, NULL, "12345", "subitem", "______", NULL);
	SIT_ListInsertItem(cb, -1, NULL, NULL, "[][][]", "&&&&&&", "------", NULL);
	#else
	int i;
	for (i = 1; i <= 20; i ++)
	{
		TEXT name[16], num[16];
		sprintf(name, "File%d.xyz", rand() % 20 + 1);
		sprintf(num, "%d", i);
		SIT_ListInsertItem(cb, -1, NULL, NULL, name, num, "---", NULL);
	}
	#endif
	SIT_AddCallback(cb, SITE_OnSortItem, sort_item, NULL);
	SIT_AddCallback(cb, SITE_OnChange, handle_lb_click, NULL);
	SIT_AddCallback(edit, SITE_OnChanged, autocomplete, cb);
	SIT_ManageWidget(dialog);
	SIT_SetFocus(edit);
}

static int show_f1(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_OnKey * msg = cd;
	if (msg->keycode == SITK_F1) {
		fprintf(stderr, "displaying tooltip ...\n");
		SIT_ShowTooltip(ud);
		return 1;
	}
	return 0;
}

static void tooltip(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("ToolTip", SIT_DIALOG, parent,
		SIT_Title,   "Tooltip test",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);
	SIT_CreateWidgets(dialog,
		"<editbox name=edit title='Hit F1 to display tooltip' width=300 minWidth=150 left=FORM right=FORM>"
	);
	SIT_Widget edit = SIT_GetById(dialog, "edit");
	SIT_Widget tool = SIT_CreateWidget("tip", SIT_TOOLTIP, edit,
		SIT_Styles, SITV_TooltipBalloon | SITV_TooltipSticky,
		SIT_Title,  "Characters \\ / : \" < > | ? and * cannot be used in filename",
		NULL
	);
	SIT_AddCallback(edit, SITE_OnRawKey, show_f1, tool);
	SIT_ManageWidget(dialog);
}

/*
 * Dynamic menu edition
 */
static int change_menu(SIT_Widget w, APTR cd, APTR ud)
{
	static SIT_MenuStruct submenu[] = {
		{1, "&Recent files", NULL, 0, 108},
			{2, "C:\\Program Files\\Polkadots Software\\Send-it\\httpd.conf",    NULL, 0, 1080},
			{2, "C:\\Program Files\\Polkadots Software\\Send-it\\track-it.conf", NULL, 0, 1081},
			{2, "C:\\Program Files\\Polkadots Software\\Send-it\\planner.conf",  NULL, 0, 1082},
			{2, "C:\\Program Files\\Polkadots Software\\Send-it\\planner-assoc.conf",  NULL, 0, 1083},
			{2, "C:\\Program Files\\Polkadots Software\\Send-it\\web\\prepage-it-upload\\Prepage-It Upload Setup.mpkg.zip",  NULL, 0, 1083},
		{0}
	};

	SIT_MenuStruct menu = {};
	switch ((ULONG) ud) {
	case 1:
		SIT_AlterMenu(w, SITM_Delete, 1020, NULL);
		break;
	case 2:
		menu.menuid = 106;
		menu.shortcut = DontChangePtr;
		menu.label = "H&i-scores...";
		SIT_AlterMenu(w, SITM_Edit, &menu, NULL);
		break;
	case 3:
		menu.menuid = 106;
		menu.shortcut = "I";
		menu.label = DontChangePtr;
		SIT_AlterMenu(w, SITM_Edit, &menu, NULL);
		break;
	case 4:
		menu.menuid = 107;
		menu.shortcut = NULL;
		menu.label = SITM_SEPARATOR;
		SIT_AlterMenu(w, SITM_Edit, &menu, NULL);
		break;
	case 5:
		SIT_AlterMenu(w, SITM_Append, 100, -1, submenu, NULL);
	}
	return 1;
}

static void dynmenu(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("DynMenu", SIT_DIALOG, parent,
		SIT_Title,   "Dynmenu test",
		SIT_Margins, 10, 10, 10, 10,
		SIT_Menu,    menu,
		NULL
	);
#if 0
static SIT_MenuStruct menu[] =
{
	{1, "&Game", NULL, 0, 100},
		{2, "&Start",    "N", 0, 101},
		{2, "S&ettings", NULL, 0, 1020},
			{3, "Easy",      NULL, SITM_Toggle(103) | SITM_Checked, 102},
			{3, "Normal",    NULL, SITM_Toggle(104), 103},
			{3, "Expert",    NULL, SITM_Toggle(105), 104},
			{3, "Custom...", "C", 0, 105},
		{2, "&Auto discover"},
			{3, "Empty cells only",  NULL, SITM_Toggle(1081), 1080},
			{3, "Obvious flags",     NULL, SITM_Checked, 1081},
			{3, "Show probability",  NULL, 0, 1082},
		{2, "S&cores...", "H", SITM_Disabled, 106},
		{2, SITM_SEPARATOR},
		{2, "E&xit",      "Q",  0, 107},
	{0}
};
#endif
	SIT_CreateWidgets(dialog,
		"<button name=delset title='Delete Settings' margins=2,5,2,5>"
		"<button name=chgsco title='Change score'    margins=2,5,2,5 top=WIDGET,delset,5>"
		"<button name=chgacc title='Change accel'    margins=2,5,2,5 top=WIDGET,chgsco,5>"
		"<button name=setsep title='Change quit'     margins=2,5,2,5 top=WIDGET,chgacc,5>"
		"<button name=addsub title='Add sub menu'    margins=2,5,2,5 top=WIDGET,setsep,5>"
	);
	SIT_AddCallback(SIT_GetById(dialog, "delset"), SITE_OnActivate, change_menu, (APTR) 1);
	SIT_AddCallback(SIT_GetById(dialog, "chgsco"), SITE_OnActivate, change_menu, (APTR) 2);
	SIT_AddCallback(SIT_GetById(dialog, "chgacc"), SITE_OnActivate, change_menu, (APTR) 3);
	SIT_AddCallback(SIT_GetById(dialog, "setsep"), SITE_OnActivate, change_menu, (APTR) 4);
	SIT_AddCallback(SIT_GetById(dialog, "addsub"), SITE_OnActivate, change_menu, (APTR) 5);
	SIT_AddCallback(dialog, SITE_OnMenu, show_menu, NULL);
	SIT_ManageWidget(dialog);
}

/*
 * Modal event loop
 */
static int exit_now(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_Exit(1234);
	return 1;
}

static int start_modal(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_Widget dialog = SIT_CreateWidget("ModalDiag", SIT_DIALOG, w,
		SIT_Title,      "Modal dialog",
		SIT_Margins,    10, 10, 10, 10,
		SIT_DialogType, SITV_ModalEvt,
		SIT_Width,      200,
		SIT_Height,     150,
		NULL
	);
	SIT_CreateWidgets(dialog,
		"<button name=quit title='Exit now' margins=2,5,2,5"
		" left=", SITV_AttachPosition, SITV_AttachPos(50), SITV_OffsetCenter,
		" top=",  SITV_AttachPosition, SITV_AttachPos(50), SITV_OffsetCenter, ">"
	);
	SIT_AddCallback(SIT_GetById(dialog, "quit"), SITE_OnActivate, exit_now, dialog);
	fprintf(stderr, "starting dialog...\n");
	SIT_ManageWidget(dialog);
	fprintf(stderr, "done.\n");
	return 1;
}

static int capture_mouse(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_OnMouse * msg = cd;
	switch (msg->state) {
	case SITOM_ButtonPressed:
		SIT_SetValues(w, SIT_Cursor, SITV_CursorCrossHair, NULL);
		return 1;
	case SITOM_CaptureMove:
		fprintf(stderr, "mouse pos = %dx%d\n", msg->x, msg->y);
		break;
	case SITOM_ButtonReleased:
		SIT_SetValues(w, SIT_Cursor, SITV_CursorNormal, NULL);
	}
	return 0;
}

static void modalloop(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("ModalLoop", SIT_DIALOG, parent,
		SIT_Title,   "Modal event loop test",
		SIT_Margins, 10, 10, 10, 10,
		SIT_Width,   250,
		SIT_Height,  200,
		NULL
	);
	SIT_CreateWidgets(dialog,
		"<button name=start title='Start modal loop' margins=2,5,2,5"
		" left=", SITV_AttachPosition, SITV_AttachPos(50), SITV_OffsetCenter,
		" top=",  SITV_AttachPosition, SITV_AttachPos(50), SITV_OffsetCenter, ">"
		"<button name=cap title='Start capture' margins=2,5,2,5 top=WIDGET,start,5"
		" left=OPPOSITE,start>"
	);
	SIT_AddCallback(SIT_GetById(dialog, "start"), SITE_OnActivate,  start_modal, dialog);
	SIT_AddCallback(SIT_GetById(dialog, "cap"),   SITE_OnClick,     capture_mouse, dialog);
	SIT_AddCallback(SIT_GetById(dialog, "cap"),   SITE_OnMouseMove, capture_mouse, dialog);
	SIT_ManageWidget(dialog);
}

/*
 * Splitter test
 */
static void splitter(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("splitter", SIT_DIALOG, parent,
		SIT_Title,   "Splitter test",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);

	SIT_CreateWidgets(dialog,
		"<canvas name=left background=", RGB(255,128,0), "frameStyle=", SITV_Sunken,
		" left=FORM top=FORM bottom=FORM width=250 minWidth=100 height=200/>"
		"<splitter name=split top=FORM bottom=FORM left=WIDGET,left,3 handleStyle=", SITV_VerticalBar, ">"
		"<canvas name=right background=", RGB(0,128,255), "frameStyle=", SITV_Sunken,
		" right=FORM top=FORM bottom=FORM left=WIDGET,split,3 width=250 minWidth=100 height=200/>"
	);

	SIT_ManageWidget(dialog);
}

/*
 * Popup menu
 */
static SIT_MenuStruct pmenu[] = {
	{1, "Test menu"},
		{2, "Color test",          NULL, 0, 101},
		{2, "Set maxLines to 10",  NULL, 0, 102},
		{2, "Set maxLines to 300", NULL, 0, 103},
		{2, "CP437 test",          NULL, 0, 104},
		{2, "Add line test",       NULL, 0, 105},
	{0}
};

static int showmenu(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_PopupMenu(ud, pmenu, 0, SITV_AlignBottom, w);
	return 1;
}

static void popupmenu(SIT_Widget parent)
{
	SIT_Widget dialog = SIT_CreateWidget("popupmenu", SIT_DIALOG, parent,
		SIT_Title,   "Popup menu test",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);

	SIT_CreateWidgets(dialog, "<button name=menu title='Show menu'>");
	SIT_AddCallback(SIT_GetById(dialog, "menu"), SITE_OnActivate, showmenu, dialog);

	SIT_ManageWidget(dialog);
}

/*
 * Generic test widget
 */
static int close(SIT_Widget w, APTR cd, APTR ud)
{
	SIT_CloseDialog(w);
	return 1;
}

ULONG LEVEL_GetBiomeColor(int id)
{
	struct Biome_t
	{
		int    id;
		ULONG  color;
		STRPTR name;
	};

	static struct Biome_t biomes[] = {
		{ 0, RGB(0x0d, 0x33, 0xdb), "Ocean"},
		{ 1, RGB(0x68, 0xde, 0x68), "Plains"},
		{ 2, RGB(0xe2, 0xf2, 0x83), "Desert"},
		{ 3, RGB(0xab, 0x69, 0x22), "Extreme Hills"},
		{ 4, RGB(0x28, 0xb5, 0x16), "Forest"},
		{ 5, RGB(0x20, 0x6e, 0x16), "Taiga"},
		{ 6, RGB(0x6c, 0x9e, 0x4f), "Swampland"},
		{ 7, RGB(0x0e, 0x7f, 0xe3), "River"},
		{ 8, RGB(0x00, 0x00, 0x00), "Nether"},
		{ 9, RGB(0x00, 0x00, 0x00), "Sky"},
		{10, RGB(0xab, 0xd8, 0xff), "Frozen Ocean"},
		{11, RGB(0xab, 0xd8, 0xff), "Frozen River"},
		{12, RGB(0x9c, 0xd6, 0xbe), "Ice Plains"},
		{13, RGB(0x97, 0xa2, 0x82), "Ice Mountains"},
		{14, RGB(0xf2, 0xd8, 0xb3), "Mushroom Island"},
		{15, RGB(0xdb, 0xc4, 0xa4), "Mushroom Island Shore"},
		{16, RGB(0xff, 0xfe, 0xbd), "Beach"},
		{17, RGB(0xe6, 0xca, 0x4e), "Desert Hills"},
		{18, RGB(0x59, 0xb0, 0x20), "Forest Hills"},
		{19, RGB(0x42, 0x6e, 0x16), "Taiga Hills"},
		{20, RGB(0xba, 0x9f, 0x27), "Extreme Hills Edge"},
		{21, RGB(0x1a, 0x57, 0x22), "Jungle"},
		{22, RGB(0x49, 0x69, 0x21), "Jungle Hills"}
	};
	if (0 <= id && id <= DIM(biomes))
		return biomes[id].color;
	return 0;
}

static void testwidgets(SIT_Widget parent)
{
	static SIT_ToolButton buttons[] = {
		{101, "RENDER !", SITTB_Button},
		{SITTB_Separator},
		{102, NULL, SITTB_Button|SITTB_Disabled, SITB_FileSave},
		{SITTB_Separator},
		{300, NULL, SITTB_Button|SITTB_Toggle(302)|SITTB_Checked, SITB_Copy},
		{301, NULL, SITTB_Button|SITTB_Toggle(302), SITB_Cut, "Brush 2x2px"},
		{302, NULL, SITTB_Button|SITTB_Toggle(303), SITB_Paste, "Brush 4x4px"},
		{303, NULL, SITTB_Button|SITTB_Toggle(304), SITB_Delete, "Brush 6x6px"},
		{304, NULL, SITTB_Button, SITB_FileOpen, "Brush 8x8px"},
		{201, NULL, SITTB_Button|SITTB_Disabled, SITB_Undo},
		{202, NULL, SITTB_Button|SITTB_Disabled, SITB_Redo},
		{SITTB_Separator},
		{305, NULL, SITTB_Child},
		{500, NULL, SITTB_Child},
		{}
	};
	SIT_Widget dialog = SIT_CreateWidget("MainWnd", SIT_DIALOG, parent,
		SIT_Title,   "Cartograph",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);

	SIT_CreateWidgets(dialog,
		"<toolbar name=tool toolbarStyle=", SITV_ToolBarList, ">"
		"  <label name=biometxt title='Biome: '>"
		"  <label name=progress title='' marginLeft=5>"
		"</toolbar>"
		"<frame name=world title=World margins=10,10,10,10 top=WIDGET,tool left=FORM right=FORM/>"
	);
	SIT_AssignToolButtons(SIT_GetById(dialog, "tool"), buttons, 305, SIT_GetById(dialog, "biometxt"),
		500, SIT_GetById(dialog, "progress"), 0);
	SIT_ManageWidget(dialog);
}

/*
 *  XXX TODO
 */

static int draw(SIT_Widget w, APTR gc, APTR ud)
{
	int points[] = {50, 10, 40, 40, -40, 40, -40, -40};
	GFX_SetPen(gc, 5, RGB(255, 0, 0));
	GFX_SetBgColor(gc, RGB(255, 160, 0));
	GFX_FillPolygon(gc, points, DIM(points)/2, GFX_CoordModePrevious | GFX_BezierCurve | GFX_ClosePolygon);

	Image img = ud;
	if (ud) GFX_SetPixels(ud, 0, 0, img->width, img->height, gc, 50, 30, 0, 0);

	return 1;
}

static int show(SIT_Widget w, APTR cd, APTR ud)
{
	Bool vis;
	SIT_GetValues(ud, SIT_Visible, &vis, NULL);
	SIT_SetValues(ud, SIT_Visible, !vis, SIT_Height, 100, NULL);
	return 1;
}

static void tab_reflow_2(SIT_Widget parent)
{
	/*static SIT_ToolButton buttons[] = {
		{101, "&File",      SITTB_Button},
		{102, "&Edit",      SITTB_Button},
		{103, "&Favorites", SITTB_Button},
		{104, "&Tools",     SITTB_Button},
		{105, "&Help",      SITTB_Button},
		{}
	};*/

	SIT_Widget dialog = SIT_CreateWidget("tab_reflow_2", SIT_DIALOG, parent,
		SIT_Title,   "MyApp",
		SIT_Margins, 10, 10, 10, 10,
		NULL
	);
	SIT_CreateWidgets(dialog,
		"<tab name=tab tabStr='First\tSecond\tThird\tFourth\tFifth\tSixth' left=FORM right=FORM minWidth=150>"
		"  <frame name=frame1 title='Frame 1' left=FORM top=FORM right=FORM tabOrder=", SITV_TabNum(1, 0), ">"
		"    <canvas name=image left=FORM frameStyle=", SITV_Sunken, "width=50 height=50/>"
		"    <progress name=pb left=FORM right=FORM top=WIDGET,image,5 progressPos=50 title='%02d%%'>"
		"    <slider name=slide left=FORM right=FORM top=WIDGET,pb,5 sliderPos=50 pageSize=10 tickFreq=10>"
		"  </frame>"
		"  <frame name=frame2 title='Frame 2' left=FORM top=FORM right=FORM tabOrder=", SITV_TabNum(2, 0), ">"
		"    <label name=labelw title='click <a href=\"http://www.google.ca\">here</a> or here.' HTMLLink=1>"
		"    <splitter name=split top=OPPOSITE,labelw bottom=OPPOSITE,labelw left=WIDGET,labelw,5>"
		"    <label name=label2 title='Antoher label' left=WIDGET,split,5>"
		"  </frame>"
		"  <editbox name=editbox placeHolder='Enter text here' left=FORM top=WIDGET,frame2,5 right=FORM"
		" tabOrder=", SITV_TabNum(2, 0), ">"
		"  <listbox name=listbox top=FORM left=FORM right=FORM bottom=FORM columnNames='Job\tDepartment\tStatus'"
		" listBoxFlags=", SITV_FullRowSelect, "tabOrder=", SITV_TabNum(3, 0),">"
		"</tab>"
//		"<toolbar name=tb toolbarStyle=", SITV_ToolBarList, "buttonList=", buttons, "/>"
		"<canvas name=draw left=FORM right=FORM top=WIDGET,tab,5 height=100 frameStyle=", SITV_Etched, "/>"
		"<button name=Ok buttonType=", SITV_DefaultButton, "top=WIDGET,draw,5>"
		"<button name=Cancel buttonType=", SITV_CancelButton, "top=OPPOSITE,Ok left=NOOVERLAP,Ok,10 right=FORM"
		" margins=0,15,0,15 maxWidth=Ok>"
		"<canvas name=preview left=FORM right=FORM top=WIDGET,Ok,5 visible=0 background=0 frameStyle=", SITV_Sunken, "/>"
	);

	#if 0
	STRPTR desc, type;
	APTR img = GFX_GetSysImage("open:small:.folder", &desc, &type);

	if (img) fprintf(stderr, "Desc = '%s', Type = '%s'\n", desc, type);
	#else
	APTR img = NULL;
	#endif

	SIT_AddCallback(SIT_GetById(dialog, "draw"), SITE_OnPaint, draw, img);
	SIT_AddCallback(SIT_GetById(dialog, "preview"), SITE_OnPaint, nuthing, img);
	SIT_AddCallback(SIT_GetById(dialog, "Ok"), SITE_OnActivate, show, SIT_GetById(dialog, "preview"));

	SIT_ManageWidget(dialog);
}
